﻿namespace Known.EntityFramework;

class EFCoreQueryBuilder<T>(IQueryable<T> query) : IQueryBuilder<T> where T : class, new()
{
    //private readonly EFCoreDatabase db = db;
    //private IQueryable<T> query = db.ctx.Set<T>();

    public string WhereSql { get; private set; }
    public Dictionary<string, object> Parameters { get; private set; }

    public IQueryBuilder<TItem> Select<TItem>(Expression<Func<T, TItem>> selector) where TItem : class, new()
    {
        var builder = new EFCoreQueryBuilder<TItem>(query.Select(selector));
        return builder;
    }

    public IQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
    {
        query = query.Where(predicate);
        return this;
    }

    public IQueryBuilder<T> GroupBy(Expression<Func<T, object>> selector)
    {
        //query = query.GroupBy(selector);
        return this;
    }

    public IQueryBuilder<T> OrderBy(Expression<Func<T, object>> selector)
    {
        query = query.OrderBy(selector);
        return this;
    }

    public IQueryBuilder<T> ThenBy(Expression<Func<T, object>> selector)
    {
        query = (query as IOrderedQueryable<T>).ThenBy(selector);
        return this;
    }

    public IQueryBuilder<T> OrderByDescending(Expression<Func<T, object>> selector)
    {
        query = query.OrderByDescending(selector).ThenByDescending(selector);
        return this;
    }

    public IQueryBuilder<T> ThenByDescending(Expression<Func<T, object>> selector)
    {
        query = (query as IOrderedQueryable<T>).ThenByDescending(selector);
        return this;
    }

    public Task<int> CountAsync() => query.CountAsync();

    public async Task<bool> ExistsAsync()
    {
        var count = await CountAsync();
        return count > 0;
    }

    public Task<T> FirstAsync() => query.FirstOrDefaultAsync();

    public async Task<TItem> FirstAsync<TItem>()
    {
        var item = await query.FirstOrDefaultAsync();
        return Utils.MapTo<TItem>(item);
    }

    public Task<List<T>> ToListAsync() => query.ToListAsync();

    public async Task<List<TItem>> ToListAsync<TItem>()
    {
        var lists = await query.ToListAsync();
        return lists?.Select(Utils.MapTo<TItem>).ToList();
    }
}